/*
 * GameController.h
 *
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses 
 */

#ifndef GAMECONTROLLER_H_
#define GAMECONTROLLER_H_

#include <map>
#include <list>
#include "Map.h"
#include "Bomberman.h"
#include "LivingObject.h"
#include "Bomb.h"
#include "GameEventObserver.h"
#include "Spawner.h"
#include "Constantes.h"
#include <utility>

enum {OBJECT, DROP};

// Controlador del game loop y el juego en curso

class GameController {
private:
    bool running;
    int id_count;
    std::list<GameEventObserver*> observers;
    std::map<int, Bomberman*> bombermans;
    std::map<int, LivingObject*> living_objects;
    std::map<int, MapObject*> solids;
    std::list<std::pair<Spawner*, bool> > spawners;
    Map& map;
    int remaining_enemies;

public:
    GameController(Map& map);
    void setRemainingEnemies(int enemies);
    int getRemainingEnemies();
    // Agrega un Observer, que se añadirá a los objetos que se agreguen al
    // controlador. Es importante cargar todos los observers antes de
    // agregar los objetos
    void addObserver(GameEventObserver* observer);
    int addBomberman(Bomberman* bomberman);
    Bomberman* getBomberman(int id);
    // level indica si el objeto se inserta en el mapa como objeto o como drop
    int addLivingObject(LivingObject* object, int level = OBJECT);
    LivingObject* getLivingObject(int id);
    int addSolid(MapObject* solid, int level = OBJECT);
    MapObject* getSolid(int id);
    // isAnObject identifica si el Spawner también es un objeto, para no
    // eliminarlo en caso de que se agote ni borrarlo más de una vez
    void addSpawner(Spawner* spawner, bool isAnObject = false);
    bool isRunning();
    GameState getState();
    void startGame();
    void stopGame();
    ~GameController();
private:
    // Agrega los observers a los objetos, les da un id, y los inserta en el
    // mapa en el nivel indicado
    int setUpObject(MapObject* object, int level = OBJECT);
    // Sleep pero en milisegundos
    void milisleep(int miliseconds);
    // Elimina y quita de las listas los objetos destuidos y los spawners
    // agotados
    void cleanUp();
    // Si encuentra un spawn de bomberman libre, restaura y reinserta al
    // bomberman pasado por parámetro
    void reinsertBomberman(Bomberman* bomberman);
};

#endif /* GAMECONTROLLER_H_ */
